﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace SimpleCore
{
    public abstract class Fsm : IFsm
    {
        /// <summary>
        /// 初始创建调用AddNodes添加默认节点。
        /// 状态机默认拥有None节点，并且设置当前状态为None。
        /// </summary>
        public Fsm()
        {
            AddNodes();
            
            AddNode<NoneFsmNode>();
            ChangeNode<NoneFsmNode>();
        }

        /// <summary>
        /// 关闭状态机。切换状态为None。
        /// </summary>
        public void Close()
        {
            ChangeNode<NoneFsmNode>();
        }

        /// <summary>
        /// 切换状态。调用上一个节点的Exit，再调用当前节点的Enter
        /// </summary>
        /// <param name="arg"></param>
        /// <typeparam name="T"></typeparam>
        public void ChangeNode<T>(object arg = null) where T : FsmNode
        {
            var key = typeof(T);
            
            if (CurrentFsmNode?.GetType() == key)
            {
                return;
            }
            
            if (NodeMap.TryGetValue(key, out var node))
            {
                CurrentFsmNode?.Exit();
                
                CurrentFsmNode = node;
                CurrentFsmNode.Enter(arg);
            }
        }

        /// <summary>
        /// 根据需求外部调用。Update
        /// </summary>
        /// <param name="interval"></param>
        public void Update(float interval)
        {
            CurrentFsmNode.Update(interval);
        }

        /// <summary>
        /// 添加状态节点
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void AddNode<T>() where T : FsmNode, new()
        {
            if (NodeMap.ContainsKey(typeof(T)))
            {
                return;
            }
            NodeMap.Add(typeof(T), new T());
        }
        
        /// <summary>
        /// 模版方法，创建时调用，用来添加默认状态节点。
        /// </summary>
        protected abstract void AddNodes();

        public FsmNode CurrentNode { get; }

        protected FsmNode CurrentFsmNode;
        protected Dictionary<Type, FsmNode> NodeMap = new Dictionary<Type, FsmNode>();
    }
}
